#pragma once

#include <QString>
#include <QIcon>
#include <QUuid>
#include <QDateTime>
#include <QFile>
#include <QDebug>
#include <QFileInfo>

#include "base.qpb.h"
#include "gateway.qpb.h"
#include "user.qpb.h"
#include "friend.qpb.h"
#include "file.qpb.h"
#include "notify.qpb.h"
#include "speech_recognition.qpb.h"
#include "message_storage.qpb.h"
#include "message_transmit.qpb.h"

namespace model {

//////////////////////////////////
/// 工具函数，可能在多个文件中使用
//////////////////////////////////

// QFile是操作文件的， QFileInfo是操作文件属性的
static inline QString getFileName(const QString& path) {
    QFileInfo fileInfo(path);
    return fileInfo.fileName();
}

//封装一个宏，用来打印日志
#define TAG QString("[%1 : %2]").arg(model::getFileName(__FILE__), QString::number(__LINE__))

//qDebug打印时或自动带上 "" ,noquote函数可以在打印时去掉 ""
#define LOG() qDebug().noquote() << TAG

// 格式化时间
static inline QString formatTime(int64_t timestamp) {
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
    return dateTime.toString("MM-dd HH:mm:ss");
}

// 获得秒级别的时间戳
static inline int64_t getTime() {
    return QDateTime::currentSecsSinceEpoch();
}

// 由 QByteArray 转化为 QIcon
static inline QIcon makeIcon(const QByteArray& byteArray) {
    QPixmap pixmap;
    pixmap.loadFromData(byteArray);
    QIcon icon(pixmap);
    return icon;
}

// 读取指定文件的数据，得到一个QByteArray
static inline QByteArray loadFileToByteArray(const QString& path) {
    QFile file(path);
    bool flag = file.open(QFile::ReadOnly);
    if(!flag) {
        LOG() << "文件打开失败！";
        return QByteArray();
    }
    QByteArray content = file.readAll();
    file.close();
    return content;
}

// 把 QByteArray 中的内容写到指定文件中
static inline void writeByteArrayToFile(const QString& path, const QByteArray& byteArray) {
    QFile file(path);
    bool flag = file.open(QFile::WriteOnly);
    if(!flag) {
        LOG() << "文件打开失败！";
        return;
    }
    file.write(byteArray);
    file.flush();
    file.close();
}

//////////////////////////////////
/// 用户信息
//////////////////////////////////

class UserInfo {
public:
    QString userId = "";          //用户编号
    QString nickname = "";       //用户昵称
    QString description = "";    //用户签名
    QString phone = "";          //手机号码
    QIcon avatar;                //用户头像

    void load(const bite_im::UserInfo userInfo) {
        this->userId = userInfo.userId();
        this->nickname = userInfo.nickname();
        this->description = userInfo.description();
        this->phone = userInfo.phone();
        if(userInfo.avatar().isEmpty()) {
            this->avatar = QIcon(":/resource/image/defaultAvatar.png");
        } else {
            this->avatar = makeIcon(userInfo.avatar());
        }
    }
};

//////////////////////////////////
/// 消息信息
//////////////////////////////////

enum MessageType {
    TEXT_TYPE,      // 文本消息
    IMAGE_TYPE,     // 图片消息
    FILE_TYPE,      // 文件消息
    SPEECH_TYPE     // 语音消息
};

class Message {
public:
    QString messageId = "";                 // 消息编号
    QString chatSessionId = "";             // 消息所属会话的编号
    QString time = "";                      // 消息的时间， 格式化 01-11 21：02：58
    MessageType messageType = TEXT_TYPE;    // 消息类型
    UserInfo sender;                        // 发送者的信息
    QByteArray content;                     // 消息的正文内容
    QString fileId = "";                    // 文件编号，当消息类型为‘文件、图片、语音’时才会用，消息类型为文本时为""
    QString fileName = "";                  // 文件名称，当消息类型为‘文件’时才有用

    static Message makeMessage(MessageType messageType, const QString& chatSessionId, const UserInfo& sender,
                               const QByteArray& content, const QString& extraInfo) {
        if(messageType == TEXT_TYPE) {
            return makeTextMessage(chatSessionId, sender, content);
        } else if(messageType == IMAGE_TYPE) {
            return makeImageMessage(chatSessionId, sender, content);
        } else if(messageType == FILE_TYPE) {
            return makeFileMessage(chatSessionId, sender, content, extraInfo);
        } else if(messageType == SPEECH_TYPE) {
            return makeSpeechMessage(chatSessionId, sender, content);
        } else {
            return Message();
        }
    }

    void load(const bite_im::MessageInfo& messageInfo) {
        this->messageId = messageInfo.messageId();
        this->chatSessionId = messageInfo.chatSessionId();
        this->time = formatTime(messageInfo.timestamp());
        this->sender.load(messageInfo.sender());

        // 设置消息类型
        auto type = messageInfo.message().messageType();
        if (type == bite_im::MessageTypeGadget::MessageType::STRING) {
            this->messageType = TEXT_TYPE;
            this->content = messageInfo.message().stringMessage().content().toUtf8();
        } else if (type == bite_im::MessageTypeGadget::MessageType::IMAGE) {
            this->messageType = IMAGE_TYPE;
            if (messageInfo.message().imageMessage().hasImageContent()) {
                this->content = messageInfo.message().imageMessage().imageContent();
            }
            if (messageInfo.message().imageMessage().hasFileId()) {
                this->fileId = messageInfo.message().imageMessage().fileId();
            }
        } else if (type == bite_im::MessageTypeGadget::MessageType::FILE) {
            this->messageType = FILE_TYPE;
            if (messageInfo.message().fileMessage().hasFileContents()) {
                this->content = messageInfo.message().fileMessage().fileContents();
            }
            if (messageInfo.message().fileMessage().hasFileId()) {
                this->fileId = messageInfo.message().fileMessage().fileId();
            }
            this->fileName = messageInfo.message().fileMessage().fileName();
        } else if (type == bite_im::MessageTypeGadget::MessageType::SPEECH) {
            this->messageType = SPEECH_TYPE;
            if (messageInfo.message().speechMessage().hasFileContents()) {
                this->content = messageInfo.message().speechMessage().fileContents();
            }
            if (messageInfo.message().speechMessage().hasFileId()) {
                this->fileId = messageInfo.message().speechMessage().fileId();
            }
        } else {
            // 错误的类型, 啥都不做了, 只是打印一个日志
            LOG() << "非法的消息类型! type=" << type;
        }
    }

private:

    static QString makeId() {
        return "M" + QUuid::createUuid().toString().sliced(25, 12);
    }

    static Message makeTextMessage(const QString& chatSessionId, const UserInfo& sender,const QByteArray& content) {
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.messageType = TEXT_TYPE;
        message.content = content;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.fileId = "";
        message.fileName = "";
        return message;
    }

    static Message makeImageMessage(const QString& chatSessionId, const UserInfo& sender,const QByteArray& content) {
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.messageType = IMAGE_TYPE;
        message.content = content;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.fileId = "";
        message.fileName = "";
        return message;
    }

    static Message makeFileMessage(const QString& chatSessionId, const UserInfo& sender,const QByteArray& content,
                                   const QString& fileName) {
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.messageType = FILE_TYPE;
        message.content = content;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.fileId = "";
        message.fileName = fileName;
        return message;
    }

    static Message makeSpeechMessage(const QString& chatSessionId, const UserInfo& sender,const QByteArray& content) {
        Message message;
        message.messageId = makeId();
        message.chatSessionId = chatSessionId;
        message.messageType = SPEECH_TYPE;
        message.content = content;
        message.sender = sender;
        message.time = formatTime(getTime());
        message.fileId = "";
        message.fileName = "";
        return message;
    }
};

//////////////////////////////////
/// 会话信息
//////////////////////////////////

class ChatSessionInfo {
public:
    QString chatSessionId = "";         //会话编号
    QString chatSessionName = "";       //会话名称，如果会话是单聊，那么会话名字为好友名字，否则就为群聊名称
    Message lastMessage;                //表示会话中的最新消息
    QIcon avatar;                       //会话头像，如果会话是单聊，那么会话头像为好友头像，否则就为群聊头像
    QString userId = "";                //单聊表示该会话对方的用户编号，群聊为""

    void load(const bite_im::ChatSessionInfo& chatSessionInfo) {
        this->chatSessionId = chatSessionInfo.chatSessionId();
        this->chatSessionName = chatSessionInfo.chatSessionName();
        if (chatSessionInfo.hasSingleChatFriendId()) {
            this->userId = chatSessionInfo.singleChatFriendId();
        }
        if (chatSessionInfo.hasPrevMessage()) {
            lastMessage.load(chatSessionInfo.prevMessage());
        }
        if (chatSessionInfo.hasAvatar() && !chatSessionInfo.avatar().isEmpty()) {
            // 已经有头像了, 直接设置这个头像
            this->avatar = makeIcon(chatSessionInfo.avatar());
        } else {
            // 如果没有头像, 则根据当前会话是单聊还是群聊, 使用不同的默认头像.
            if (userId != "") {
                // 单聊
                this->avatar = QIcon(":/resource/image/defaultAvatar.png");
            } else {
                // 群聊
                this->avatar = QIcon(":/resource/image/groupAvatar.png");
            }
        }
    }
};

} // end model
